﻿#include "AdvanceScene.h"

#include <map>

#include "Camera.h"
#include "Debuger.h"
#include "FMeshWithOutline.h"
#include "Mesh.h"
#include "Render.h"
#include "MaterialSrc/CubeMaterial.h"
#include "MaterialSrc/TranspareMaterial.h"

static float GCubeVertices[] = {
	// Back face
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f, // Bottom-left
	0.5f,  0.5f, -0.5f,  1.0f, 1.0f, // top-right
	0.5f, -0.5f, -0.5f,  1.0f, 0.0f, // bottom-right         
	0.5f,  0.5f, -0.5f,  1.0f, 1.0f, // top-right
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f, // bottom-left
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f, // top-left
									  // Front face
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f, // bottom-left
	0.5f, -0.5f,  0.5f,  1.0f, 0.0f, // bottom-right
	0.5f,  0.5f,  0.5f,  1.0f, 1.0f, // top-right
	0.5f,  0.5f,  0.5f,  1.0f, 1.0f, // top-right
	-0.5f,  0.5f,  0.5f,  0.0f, 1.0f, // top-left
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f, // bottom-left
									// Left face
	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // top-right
	-0.5f,  0.5f, -0.5f,  1.0f, 1.0f, // top-left
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // bottom-left
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // bottom-left
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f, // bottom-right
	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // top-right
	// Right face
	0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // top-left
	0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // bottom-right
	0.5f,  0.5f, -0.5f,  1.0f, 1.0f, // top-right         
	0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // bottom-right
	0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // top-left
	0.5f, -0.5f,  0.5f,  0.0f, 0.0f, // bottom-left     
	// Bottom face
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // top-right
	0.5f, -0.5f, -0.5f,  1.0f, 1.0f, // top-left
	0.5f, -0.5f,  0.5f,  1.0f, 0.0f, // bottom-left
	0.5f, -0.5f,  0.5f,  1.0f, 0.0f, // bottom-left
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f, // bottom-right
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f, // top-right
	// Top face
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f, // top-left
	0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // bottom-right
	0.5f,  0.5f, -0.5f,  1.0f, 1.0f, // top-right     
	0.5f,  0.5f,  0.5f,  1.0f, 0.0f, // bottom-right
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f, // top-left
	-0.5f,  0.5f,  0.5f,  0.0f, 0.0f  // bottom-left        
};

static std::vector<FVertexInfo> StaticVertices = {
	// positions          // normals           // texture coords
	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f), glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f),  glm::vec3(0.0f,  0.0f, -1.0f),  glm::vec2(0.0f, 0.0f)},

	FVertexInfo{glm::vec3(-0.5f, -0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f,  0.5f),  glm::vec3(0.0f,  0.0f, 1.0f),   glm::vec2(0.0f, 0.0f)},

	FVertexInfo{glm::vec3(-0.5f,  0.5f,  0.5f), -glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f, -0.5f), -glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f), -glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f), -glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f,  0.5f), -glm::vec3(1.0f,  0.0f,  0.0f), glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f,  0.5f), -glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},

	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f, -0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f, -0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f, -0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f,  0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(1.0f,  0.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},

	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f, -0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f,  0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f, -0.5f,  0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f,  0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f, -0.5f, -0.5f),  glm::vec3(0.0f, -1.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},

	FVertexInfo{glm::vec3(-0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(0.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(1.0f, 1.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(1.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f,  0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(0.0f, 0.0f)},
	FVertexInfo{glm::vec3(-0.5f,  0.5f, -0.5f),  glm::vec3(0.0f,  1.0f,  0.0f),  glm::vec2(0.0f, 1.0f)}
};

auto FAdvanceScene::Init(FRender* InRender) -> void
{
	FScence::Init(InRender);

	Camera = CreateDefaultCamera();

	const auto Material = std::make_shared<FCubeMaterial>();
	//TestMesh = std::make_shared<FMeshWithOutline>();
	TestMesh = std::make_shared<FMesh>();
	std::vector<FVertexInfo> CopyVertices;

	for (int32_t Index = 0; Index < 180;)
	{
		CopyVertices.push_back(
			FVertexInfo
			{
				glm::vec3(GCubeVertices[Index + 0], GCubeVertices[Index + 1],GCubeVertices[Index + 2]),
				glm::vec3(),
				glm::vec2(GCubeVertices[Index + 3], GCubeVertices[Index + 4])
			}
		);
		Index += 5;
	}

	bool Ok = TestMesh->Init(std::move(CopyVertices), Material);
	DebugerAssert(Ok, "%hs", "初始化Mesh失败");

	const auto TranspareMaterial = std::make_shared<FTranspareMaterial>();
	TransparentMesh = std::make_shared<FMesh>();
	std::vector<FVertexInfo> TranspareVertices{
		{glm::vec3(0.0f,  0.5f,  0.0f), glm::vec3(), glm::vec2(0.0f,  0.0f)},
		{glm::vec3(0.0f, -0.5f,  0.0f), glm::vec3(), glm::vec2(0.0f,  1.0f)},
		{glm::vec3(1.0f, -0.5f,  0.0f), glm::vec3(), glm::vec2(1.0f,  1.0f)},

		{glm::vec3(0.0f,  0.5f,  0.0f), glm::vec3(), glm::vec2(0.0f,  0.0f)},
		{glm::vec3(1.0f, -0.5f,  0.0f), glm::vec3(), glm::vec2(1.0f,  1.0f)},
		{glm::vec3(1.0f,  0.5f,  0.0f), glm::vec3(), glm::vec2(1.0f,  0.0f)}
	};
	Ok = TransparentMesh->Init(std::move(TranspareVertices), TranspareMaterial);
	DebugerAssert(Ok, "%hs", "Transpare 初始化Mesh失败");

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
	glEnable(GL_STENCIL_TEST);
	glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_CULL_FACE);
}

auto FAdvanceScene::Destory() -> void
{
	FScence::Destory();
}

auto FAdvanceScene::Draw(float DateTime) -> void
{
	FScence::Draw(DateTime);

	auto Projection = glm::mat4(1.f);
	Projection = glm::perspective(glm::radians(Camera->GetFOV()), Render->GetAspect(), 0.1f, 100.0f);

	const auto View = Camera->GetViewMat();

	FDrawArg DrawArg;
	DrawArg.DateTime = DateTime;
	DrawArg.LightArray = { };
	DrawArg.ViewMat = View;
	DrawArg.ViewPos = Camera->GetPosition();
	DrawArg.ProjectionMat = Projection;

	glm::mat4 ModelMat = glm::mat4(1.f);
	TestMesh->SetTransform(ModelMat);

	TestMesh->Draw(DrawArg);

	ModelMat = glm::mat4(1.f);
	ModelMat = glm::translate(ModelMat, glm::vec3(0, -0.6, 0));
	ModelMat = glm::scale(ModelMat, glm::vec3(20, 0.2, 20));
	TestMesh->SetTransform(ModelMat);
	TestMesh->Draw(DrawArg);


	std::vector<glm::vec3> windows
	{
		glm::vec3(-1.5f, 0.0f, -0.48f),
		glm::vec3(1.5f, 0.0f, 0.51f),
		glm::vec3(0.0f, 0.0f, 0.7f),
		glm::vec3(-0.3f, 0.0f, -2.3f),
		glm::vec3(0.5f, 0.0f, -0.6f)
	};

	std::map<float, glm::vec3> sorted;
	for (unsigned int i = 0; i < windows.size(); i++)
	{
		float distance = glm::length(Camera->GetPosition() - windows[i]);
		sorted[distance] = windows[i];
	}

	// 透明面片要禁用 面剔除，否则就会出现 面片直接消失
	glDisable(GL_CULL_FACE);

	for (std::map<float, glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it)
	{
		auto model = glm::mat4(1.0f);
		model = glm::translate(model, it->second);

		TransparentMesh->SetTransform(model);
		TransparentMesh->Draw(DrawArg);
	}

	glEnable(GL_CULL_FACE);

}

auto FAdvanceScene::GetCamera() const -> std::shared_ptr<FCamera>
{
	return Camera;
}
